package com.tdk.mybatisplus.demo.common.util;

import com.tdk.mybatisplus.demo.common.entity.ICodeNameMapping;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;

/**
 * <p>
 * 查找枚举
 * </p>
 *
 * @author: taodingkai
 * @modified:
 * @since: 2022/08/08 13:41
 */
@Slf4j
public class CodeNameMappingEnumUtil {

  /**
   * <p>
   * 按编码查询
   * </p>
   *
   * @param tClass
   * @param code
   * @return T
   * @author: taodingkai
   * @since: 2022/08/08 13:49
   */
  public static <T extends Enum<T> & ICodeNameMapping<K,V>,K,V> T findByCode(Class<T> tClass, K code) {
    try {
      return findByCodeOrName(tClass, code,(T mapping)->mapping.getCode());
    } catch (Exception e) {
      log.error("按编码查询枚举失败");
    }
    return null;
  }

  /**
   * <p>
   * 按名称查询
   * </p>
   *
   * @param tClass
   * @param name
   * @return T
   * @author: taodingkai
   * @since: 2022/08/08 13:49
   */
  public static <T extends Enum<T> & ICodeNameMapping<K,V>,K,V> T findByName(Class<T> tClass, V name) {
    try {
      return findByCodeOrName(tClass, name,(T mapping)->mapping.getName());
    } catch (Exception e) {
      log.error("按名称查询枚举失败");
    }
    return null;
  }

  /**
   * <p>
   * 按编码查询名称
   * </p>
   *
   * @param tClass
   * @param code
   * @return T
   * @author: taodingkai
   * @since: 2022/08/08 13:49
   */
  public static <T extends Enum<T> & ICodeNameMapping<K,V>,K,V> V findNameByCode(Class<T> tClass,  K code) {
    try {
      T t = findByCodeOrName(tClass, code,(T mapping)->mapping.getCode());
      if(Objects.nonNull(t)){
        return t.getName();
      }
    } catch (Exception e) {
      log.error("按名称查询枚举失败");
    }
    return null;
  }

  /**
   * <p>
   * findByCodeOrName
   * </p>
   *
   *
   * @param tClass
   * @param codeOrName
   * @param function
   * @return T
   * @author: taodingkai
   * @since: 2022/8/23 11:45 
   */
  private static <T extends Enum<T> & ICodeNameMapping<K, V>, K, V> T findByCodeOrName(Class<T> tClass, Object codeOrName, Function<T,Object> function) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    Method method = tClass.getMethod("values");
    return Arrays.stream((T[]) method.invoke(tClass))
            .filter(mapping->Objects.equals(function.apply(mapping),codeOrName)).findAny().orElse(null);
  }
}
